package cn.com.sbell.vss.csg.vap.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;

import cn.com.sbell.vss.Network;
import cn.com.sbell.vss.Response;
import cn.com.sbell.vss.VssConstants;
import cn.com.sbell.vss.VssException;
import cn.com.sbell.vss.csg.vsclient.util.CSGConfiguration;
import cn.com.sbell.vss.servlet.DispatchServlet;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class CSGRelayer {
	protected final static Log logger = LogFactory.getLog(CSGRelayer.class);
public static Response relayRequest(HttpServletRequest request,String routeUrl,String command)
{
//	get next hop sever ip, port , uri
	Matcher matcher=CSGConfiguration.patternRoute.matcher(routeUrl);
	logger.debug("AbstractCommander routeUrl:"+routeUrl+", matches pattern="+matcher.matches());
	String serverIp=null;
	Integer serverPort=null;
	String serverUri=null;
	matcher.matches();
	serverIp=matcher.group(1);
	serverPort=Integer.parseInt(matcher.group(2));
	serverUri=matcher.group(3);
	
//	get command
//	String cp = request.getContextPath();
//	String command = request.getRequestURI();
//	if (command.length() >= cp.length()) {
//		command = command.substring(cp.length());
//		if (command.startsWith("/")) {
//			command = command.substring(1);
//		}
//	}
	
	if (logger.isDebugEnabled())
		logger.debug("Beging CSG Routing processing");
//	(domainUsername,domainPassword)
	CrossDomainCredential authResult=null;
	try {
		authResult=RouteSessionMapper.getRoute(routeUrl, request);
		if(null==authResult)
		{
			
			throw new VssException(VssConstants.CODE_NEXTDOMAIN_AUTHENTICATE_FIAL);
		}
	} catch (VssException e) {
		// TODO: handle exception
		logger.debug("route sessionMapper,error:"+e.getResultCode()+",message"+Arrays.toString(e.getFields()));
		return generateResponse(request,e.getResultCode());
	}
	
	ArrayList includeList=new ArrayList();
	ArrayList excludeList=new ArrayList();
	
	Object[] result=new Object[2];
	if((null!=authResult.getNextDomainUserName())&&(null!=authResult.getNextDomainPassWord()))
	{
	try {
//		(response,sessionId)
		tryFirst(authResult,includeList,excludeList,routeUrl,
	    		request,serverIp,serverPort,serverUri,command, result);
		if(VssConstants.CODE_SUCCESS.equalsIgnoreCase(((Response)result[0]).getReturnCode()))
		{
			authResult.setNextDomainSessionId((String)result[1]);
			RouteSessionMapper.updateRoute(routeUrl, authResult,request);
			return (Response)result[0];
		}else if(VssConstants.CODE_AUTHENTICATION_FAILED.equalsIgnoreCase(((Response)result[0]).getReturnCode())
				||
				VssConstants.CODE_NEED_LOGIN.equalsIgnoreCase(((Response)result[0]).getReturnCode())){
			return tryAgain(includeList,excludeList,routeUrl,request,serverIp,serverPort,
					serverUri,command, (Response)result[0]);
		}else{
			return (Response)result[0];
		}
		
		
		} catch (VssException e) {
		// TODO: handle exception
			logger.debug("process relay exception error:"+e.getResultCode()+",message:"+Arrays.toString(e.getFields()));
		return generateResponse(request,e.getResultCode());
		
		}
		
	}else{
		return generateResponse(request,VssConstants.CODE_RELAY_ERROR);
		
	}

}
public static Response generateResponse(HttpServletRequest request,String resultCode)
{
	Response res = Response.createResponse(request);
	res.setReturnCode(resultCode);
	String returnMessage = DispatchServlet.getMessage("code." + res.getReturnCode(),request);
	res.setReturnMessage(returnMessage);
	return res;
}
public static Response generateResponse(HttpServletRequest request,String resultCode,Object[] args)
{
	Response res = Response.createResponse(request);
	res.setReturnCode(resultCode);
	String returnMessage = DispatchServlet.getMessage("code." + res.getReturnCode(),args,request);
	res.setReturnMessage(returnMessage);
	return res;
}
private static Response tryAgain(List includeList,List excludeList,String routeUrl,
		HttpServletRequest request,String serverIp,int serverPort,String serverUri,String command, Response result)
{
	CrossDomainCredential authAgain= RouteSessionMapper.refreshRoute(routeUrl, request);
	if(null!=authAgain)
	{
		
		includeList.clear();
		excludeList.clear();
		Object[] resultAgain=null;
		
		includeList.add(new NameValuePair("__username",authAgain.getNextDomainUserName()));
		includeList.add(new NameValuePair("__password",authAgain.getNextDomainPassWord()));
		includeList.add(new NameValuePair("route",routeUrl));
//		
		excludeList.add("__username");
		excludeList.add("__password");
		excludeList.add("username");
		excludeList.add("password");
		excludeList.add("route");
		resultAgain=	Network.sendRequestGetStr(null, serverIp, serverPort, (stringNotNull(serverUri)?("/"+serverUri):"")+"/"+command, 
				Network.makeNameValuePair(request,includeList,excludeList), true);
		if(VssConstants.CODE_SUCCESS.equalsIgnoreCase(((Response)resultAgain[0]).getReturnCode()))
		{
			authAgain.setNextDomainSessionId((String)resultAgain[1]);
			RouteSessionMapper.updateRoute(routeUrl, authAgain,request);
		}
		return (Response)resultAgain[0];
	}
	
	return result;
}
private static void tryFirst(CrossDomainCredential authResult,List includeList,List excludeList,String routeUrl,
		HttpServletRequest request,String serverIp,int serverPort,String serverUri,String command, Object[] result)
{
	
//		(response,sessionId)
		includeList.add(new NameValuePair("__username",authResult.getNextDomainUserName()));
		includeList.add(new NameValuePair("__password",authResult.getNextDomainPassWord()));
		includeList.add(new NameValuePair("route",routeUrl));
//		
		excludeList.add("__username");
		excludeList.add("__password");
		excludeList.add("username");
		excludeList.add("password");
		excludeList.add("route");
		Object[] temp=Network.sendRequestGetStr(authResult.getNextDomainSessionId(), serverIp, serverPort, (stringNotNull(serverUri)?("/"+serverUri):"")+"/"+command, 
				Network.makeNameValuePair(request,includeList,excludeList), true);
		result[0]=temp[0];
		result[1]=temp[1];
}
private static boolean stringNotNull(String s)
{
	return !((null==s)||(s.trim().length()==0));
}
}
